package com.zzl.zzlojbackendjudgeservice.judge;
import cn.hutool.json.JSONUtil;
import com.zzl.zzlojbackendcommon.common.ErrorCode;
import com.zzl.zzlojbackendcommon.exception.BusinessException;
import com.zzl.zzlojbackendjudgeservice.judge.codesandbox.CodeSandbox;
import com.zzl.zzlojbackendjudgeservice.judge.codesandbox.CodeSandboxFactory;
import com.zzl.zzlojbackendjudgeservice.judge.codesandbox.CodeSandboxProxy;
import com.zzl.zzlojbackendjudgeservice.judge.strategy.JudgeContext;
import com.zzl.zzlojbackendmodel.model.codesandbox.ExcuteCodeRequest;
import com.zzl.zzlojbackendmodel.model.codesandbox.ExcuteCodeResponse;
import com.zzl.zzlojbackendmodel.model.codesandbox.JudgeInfo;
import com.zzl.zzlojbackendmodel.model.dto.question.JudgeCase;
import com.zzl.zzlojbackendmodel.model.entity.Question;
import com.zzl.zzlojbackendmodel.model.entity.QuestionSubmit;
import com.zzl.zzlojbackendmodel.model.enums.QuestionSubmitStatusEnum;
import com.zzl.zzlojbackendserviceclient.service.QuestionFeignClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class JudgeServiceImpl implements JudgeService {
    @Resource
    private QuestionFeignClient questionFeignClient;

    @Value("${codesandbox.type}")
    private String type;
    @Resource
    private JudgeManager judgeManager;

    /**
     * 进行判题服务
     *
     * @param questionSubmitId
     * @return
     */
    @Override
    public QuestionSubmit doJudge(long questionSubmitId) {
        // 1.根据传入的题目提交信息id，获取到questionSubmit和question
        QuestionSubmit questionSubmit = questionFeignClient.getQuestionSubmitById(questionSubmitId);
        if (questionSubmit == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目提交信息不存在");
        }
        long questionId = questionSubmit.getQuestionId();
        Question question = questionFeignClient.getQuestionById(questionId);
        if (question == null) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "题目不存在");
        }
        // 2.查看questionSubmit的状态，如果已经在判题了，就抛出错误
        Integer status = questionSubmit.getStatus();
        if (!status.equals(QuestionSubmitStatusEnum.WAITING.getValue())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "请勿重复提交题目");
        }
        // 3.更改questionSubmit的判题状态
        QuestionSubmit questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setId(questionSubmitId);
        questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.PENDING.getValue());
        boolean update = questionFeignClient.updateQuestionSubmitById(questionSubmitUpdate);
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }

        // 4. 调用沙箱
        // 4.1 获取输入用例
        String judgeCaseStr = question.getJudgeCase();
        List<JudgeCase> judgeCaseList = JSONUtil.toList(judgeCaseStr, JudgeCase.class);
        List<String> inputList = judgeCaseList.stream().map(JudgeCase::getInput).collect(Collectors.toList());
        // 4.2 获取题目提交的代码和语言
        String code = questionSubmit.getCode();
        String language = questionSubmit.getLanguage();
        // 4.3创建沙箱请求
        ExcuteCodeRequest excuteCodeRequest = ExcuteCodeRequest.builder().code(code).language(language).inputList(inputList).build();
        CodeSandbox codeSandbox = CodeSandboxFactory.newInstance(type);
        codeSandbox = new CodeSandboxProxy(codeSandbox);
        ExcuteCodeResponse excuteCodeResponse = codeSandbox.excuteCode(excuteCodeRequest);

        // 5.根据沙箱返回的结果，确定题目提交答案是否成功
        List<String> outputList = excuteCodeResponse.getOutputList();
        JudgeContext judgeContext = new JudgeContext();
        judgeContext.setJudgeInfo(excuteCodeResponse.getJudgeInfo());
        judgeContext.setInputList(inputList);
        judgeContext.setOutputList(outputList);
        judgeContext.setJudgeCaseList(judgeCaseList);
        judgeContext.setQuestion(question);
        judgeContext.setQuestionSubmit(questionSubmit);
        JudgeInfo judgeInfo = judgeManager.doJudge(judgeContext);

        // 6）修改数据库中的判题结果
        questionSubmitUpdate = new QuestionSubmit();
        questionSubmitUpdate.setId(questionSubmitId);
        questionSubmitUpdate.setStatus(QuestionSubmitStatusEnum.SUCCESS.getValue());
        questionSubmitUpdate.setJudgeInfo(JSONUtil.toJsonStr(judgeInfo));
        update = questionFeignClient.updateQuestionSubmitById(questionSubmitUpdate);
        if (!update) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "题目状态更新错误");
        }
        QuestionSubmit questionSubmitResult = questionFeignClient.getQuestionSubmitById(questionId);
        return questionSubmitResult;
    }
}
